
#include "thread.h"

namespace dulymoo {

pthread_key_t Thread::key_;
bool Thread::key_initialized_ = false;
pthread_once_t Thread::key_once_ = PTHREAD_ONCE_INIT;

Thread::Thread(void (*func)(void*), void* arg, unsigned long stack_size) :
    func_(func), arg_(arg), stack_size_(stack_size), thread_(0)
{
}

Thread::~Thread()
{
}

bool Thread::Start()
{
    if (thread_ != 0)
        return true;

    pthread_attr_t attr;
    if (0 != pthread_attr_init(&attr))
        return false;
    if (stack_size_ != 0)
        pthread_attr_setstacksize(&attr, stack_size_);

    int ret = pthread_create(&thread_, &attr, ThreadProc, static_cast<void*>(this));
    pthread_attr_destroy(&attr);

    return ret == 0 ? true : false;
}

bool Thread::Join()
{
    if (thread_ == 0)
        return false;

    int ret = pthread_join(thread_, NULL);
    thread_ = 0;
    return ret == 0;
}

void* Thread::GetSpecific()
{
    if (!key_initialized_)
        pthread_once(&key_once_, InitKey);

    return pthread_getspecific(key_);
}

bool Thread::SetSpecific(void* value)
{
    if (!key_initialized_)
        pthread_once(&key_once_, InitKey);

    return 0 == pthread_setspecific(key_, value);
}

void* Thread::ThreadProc(void* arg)
{
    Thread* thread = reinterpret_cast<Thread*>(arg);
    if (thread != 0)
        (thread->func_)(thread->arg_);
    return NULL;
}

void Thread::InitKey()
{
    pthread_key_create(&key_, NULL);
    key_initialized_ = true;
}

} // namespace dulymoo

